#include <iostream>
#include <string>

class student;

void work(student s);
student work2();

class student{  //class默认权限为私有
// 空对象占用一个字节
// 非静态成员函数,属于类的对象上

// 默认情况下，编译器至少给一个类提供四个函数
// 默认构造函数、默认析构函数、默认拷贝构造函数、operator=()
// 如果用户定义了有参构造函数，C++不会提供默认构造函数，但是会提供默认拷贝构造函数（值拷贝）
// 如果用户定义了拷贝构造函数，C++不会提供其他构造函数

// 当其他类对象作为本类成员，构造时像构造类对象，再构造自身，析构的顺序与构造相反


// 成员变量和成员函数分开存储
// 成员变量
private:
    int age;
public:
    int id;
    std::string name; 

// 静态成员变量
    // 所有对象共享同一份数据
    // 编译阶段分配内存
    // 类内声明，类外初始化
    static int grade;

// 成员属性声明时加mutable后,在常函数中依然可以修改
    mutable int weight;

// 成员函数

// 构造函数
// 可以被重载
// 创建对象的时候，构造函数会自动调用，并且只会调用一次。
    // student(){
    //     std::cout<< "student 无参构造函数调用"<<std::endl;
    // }
// 初始化列表初始化数值
    student(): id(10), name("wan"), age(18){
        std::cout<< "student 无参构造函数调用"<<std::endl;
    }

    student(int id, std::string name){
        std::cout<< "student 有参构造函数调用"<<std::endl;
        this->id = id;
        this->name = name;
    }
    
// 拷贝构造函数
    student(const student &s){
        std::cout<< "student 拷贝构造函数调用"<<std::endl;
        id = s.id;
        name = s.name;
        age = s.age;
    }


// 析构函数
// 不可以有参数，因此不能被重载
    ~student(){
        std::cout<< "student 析构函数调用"<<std::endl;
    }


// 静态成员函数
// 所有对象共享同一个函数
// 静态成员函数只能访问静态成员变量
    static void func(){
        std::cout<< "静态成员函数, 变量grade：" << grade <<std::endl;
    }

// this指针
// 解决名称冲突
// 返回对象本身用*this
    student& addAge(student &s){    //加&是为了函数执行完毕后返回的是这个类本身,而不是这个类的副本
        this->age += s.age;
        return *this;
    }
// 空指针访问成员函数
    void func2(){
        std::cout<< "func2()" <<std::endl; 
    }
    void get_name(){
        // if(this == NULL) return;    //小优化
        std::cout<< "get_name():" << name <<std::endl;  //name相当于this->name
    }
// 常函数
// 成员函数后面加const
// 常函数不可以修改成员属性
    void setWeight(int w) const {
        weight = w;     
    }


// 访问类的成员变量,可以控制变量的读写
    int getid(){
        return id;
    }
    void setid(int i){
        id = i;
    }
    std::string getName(){
        return name;
    }
    void setName(std::string n){
        name = n;
    }
    void setAge(int a){
        age = a;
    }
    int getAge(){
        return age;
    }

};


void function(){
// 类的调用
// 括号法
    // student s1;
    // student s2(10, "wan");
    // student s3(s2);
    // 调用默认构造函数时，不要加（），因为编译器会把它看作一个函数的声明
    // student s1();    //错误

// 显示法
    // student s1 = student();
    // student s2 = student(20, "zhao");
    // student s3 = student(s2);
    // student(20, "zhao");    //匿名对象：执行结束后立刻被回收
    // 不要利用拷贝构造函数初始化匿名对象

// 隐式转换法
    // student s1 = s2;

// 拷贝构造函数调用时机
// 使用一个已经创建完毕的对象来初始化一个新对象
    // student s1(10, "wan");
    // student s2(s1);
// 值传递的方式给函数参数传值
    // student s1;
    // work(s1);
// 值方式返回局部对象
    // student s1 = work2();
    // std::cout<< (int *)&s1<<std::endl;
    // std::cout<<s1.getid()<<std::endl;
    // std::cout<<s1.getName() <<std::endl;

// 静态成员变量
    // 通过对象
    // student s1(10, "li");
    // std::cout<< s1.grade <<std::endl;
    // 通过类名
    // std::cout<< student::grade <<std::endl;

// 静态成员函数 
    // 通过对象
    // student s1;
    // s1.func();
    // 通过类名
    // student::func();

// 返回对象本身用*this
    // student s1(10,"wan");
    // s1.setAge(18);
    // student s2(20,"zhao");
    // s2.setAge(20);
    // s1.addAge(s2).addAge(s2).addAge(s2);
    // std::cout<< s1.getAge() <<std::endl;

// 空指针访问成员函数
    // student *s = NULL;
    // s->func2();     //不会报错,因为func2()没有使用未实体化类中的成员变量,也就是说func2()中没有this指针
    // s->get_name();      //会报错,因为get_name()使用了this指针

// const修饰成员函数
// 常对象
// 声明对象前加const
// 常对象只能调用常函数
    const student s1;
    s1.setWeight(0);

}

void work(student s){

}

student work2(){
    student s(30, "zhao");
    std::cout<< (int *)&s<<std::endl;
    return s;
}

int student::grade = 0;

int main(){
    // student s1;
    // s1.setid(100);
    // s1.setName("万");
    // s1.setAge(18);
    // std::cout<< s1.getid() <<std::endl;
    // std::cout<< s1.getName() <<std::endl;
    // std::cout<< s1.getAge() <<std::endl;
    function();

    return 0;
}